//
// Created by edward on 22-11-17.
// 模拟5个哲学家进餐问题
//

#include "utils.h"
#include <mutex>
#include <atomic>
#include <string>
#include <thread>

using namespace std;
atomic_bool flag = true;

constexpr int kMaxSleepTime = 10;
constexpr int kN = 5;

vector<mutex> chopsticks(kN);

class Philosopher {
public:
    Philosopher(int idx, const string &name = string("philosopher ").append(to_string(UUID++)))
    : idx_(idx)
    , name_(name) {}
    void eat() {
        edward::print_safe(name_, "is now hungry");
        lock_guard lk0(chopsticks[idx_]), lk1(chopsticks[(idx_ + 1) % kN]); //分别获取左手边筷子和右手边筷子
        edward::print_safe(name_, "is now eating");
        this_thread::sleep_for(chrono::seconds(edward::Random::rand(kMaxSleepTime)));
    }
    void think() {
        edward::print_safe(name_, "is now thinking");
        this_thread::sleep_for(chrono::seconds(edward::Random::rand(kMaxSleepTime)));
    }
    void alive() {
        while (flag) {
            think();
            eat();
        }
    }
private:
    int idx_;   //根据idx_获取筷子，很重要
    const string name_;
    static int UUID;
};

int Philosopher::UUID = 0;

void work(int idx) {
    Philosopher(idx).alive();
}

int main() {
    vector<thread> threads;
    for (int i = 0; i < kN; ++i) {
        threads.emplace_back(work, i);
    }
    char c;
    while (cin >> c && c != 'n'); //等待输入n结束运行
    flag = false;
    for (int i = 0; i < kN; ++i) {
        threads[i].join();
    }
    return 0;
}